package com.fau.wmbj.server.controller;

import com.fau.wmbj.server.audit.Audit;
import com.fau.wmbj.server.flowable.domain.bo.ModelBo;
import com.fau.wmbj.server.flowable.pojo.ProcessModel;
import com.fau.wmbj.server.flowable.service.ActModelService;
import com.fau.wmbj.server.idempotent.annotation.RepeatSubmit;
import com.fau.wmbj.server.utils.Message;
import com.fau.wmbj.server.utils.Pageable;
import lombok.RequiredArgsConstructor;
import org.flowable.bpmn.converter.BpmnXMLConverter;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.engine.RepositoryService;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;

/**
 * 模型管理 控制层
 */
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/workflow/model")
public class ActModelController {

    private final RepositoryService repositoryService;

    private final ActModelService actModelService;


    /**
     * 分页查询模型
     *
     * @param modelBo 模型参数
     */
    @GetMapping("/list")
    public Message page(@RequestBody ModelBo modelBo, @RequestBody Pageable pageable) {
        return Message.success(actModelService.page(modelBo, pageable));
    }

    /**
     * 新增模型
     *
     * @param modelBo 模型请求对象
     */
    @Audit(action = "模型管理")
    @RepeatSubmit()
    @PostMapping("/save")
    public Message saveNewModel(@RequestBody ModelBo modelBo) {
        return Message.success(actModelService.saveNewModel(modelBo));
    }

    /**
     * 查询模型
     *
     * @param id 模型id
     */
    @GetMapping("/getInfo/{id}")
    public Message getInfo(@PathVariable String id) {
        return Message.success(actModelService.getInfo(id));
    }

    /**
     * 修改模型信息
     *
     * @param modelBo 模型数据
     */
    @RepeatSubmit()
    @PutMapping(value = "/update")
    public Message update(@RequestBody ModelBo modelBo) {
        return Message.success(actModelService.update(modelBo));
    }

    /**
     * 编辑XMl模型
     *
     * @param modelBo 模型数据
     */
    @RepeatSubmit()
    @PutMapping(value = "/editModelXml")
    public Message editModel(@RequestBody ModelBo modelBo) {
        return Message.success(actModelService.editModelXml(modelBo));
    }

    /**
     * 删除流程模型
     *
     * @param ids 模型id
     */
    @RepeatSubmit()
    @DeleteMapping("/{ids}")
    @Transactional(rollbackFor = Exception.class)
    public Message delete(@PathVariable String[] ids) {
        Arrays.stream(ids).parallel().forEachOrdered(repositoryService::deleteModel);
        return Message.success();
    }

    /**
     * 模型部署
     *
     * @param id 模型id
     */
    @RepeatSubmit()
    @PostMapping("/modelDeploy/{id}")
    public Message deploy(@PathVariable String id) {
        return Message.success(actModelService.modelDeploy(id));
    }

    /**
     * 导出模型zip压缩包
     *
     * @param modelIds 模型id
     * @param response 相应
     */
    @GetMapping("/export/zip/{modelIds}")
    public void exportZip(@PathVariable List<String> modelIds, HttpServletResponse response) {
        actModelService.exportZip(modelIds, response);
    }

    /**
     * 复制模型
     *
     * @param modelBo 模型数据
     */
    @PostMapping("/copyModel")
    public Message copyModel(@RequestBody ModelBo modelBo) {
        return Message.success(actModelService.copyModel(modelBo));
    }

    /**
     * 转为bpmn，并下载
     */
    @PostMapping("/download")
    public void downloadXml(@RequestBody ProcessModel processModel) throws IOException {
        BpmnModel bpmnModel = processModel.toBpmnModel();
        byte[] xmlBytes = new BpmnXMLConverter().convertToXML(bpmnModel);
        if (Objects.nonNull(xmlBytes)) {
            String fileName = processModel.getName().replaceAll(" ", "_") + ".bpmn20.xml";
            HttpServletResponse response = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getResponse();
            if (Objects.nonNull(response)) {
                response.setContentType("application/xml");
                response.setHeader("Access-Control-Expose-Headers", "Content-Disposition");
                response.setHeader("Content-Disposition", "attachment; filename=file.bpmn20.xml; filename*=" + URLEncoder.encode(fileName, StandardCharsets.UTF_8));
                ServletOutputStream servletOutputStream = response.getOutputStream();
                BufferedInputStream in = new BufferedInputStream(new ByteArrayInputStream(xmlBytes));
                byte[] buffer = new byte[8096];
                while (true) {
                    int count = in.read(buffer);
                    if (count == -1) {
                        break;
                    }
                    servletOutputStream.write(buffer, 0, count);
                }
                // 刷新并关闭流
                servletOutputStream.flush();
                servletOutputStream.close();
            }
        }
    }
}
